
#ifndef WORKER_H_
#define WORKER_H_

#define WORKER_MAILBOX_SIZE 99999

#include <vector>
#include <iostream>
#include "RouterTable.h"
#include "Mailbox.h"
#include "OSThread.h"
#include "Message_RT.h"
#include "Message_System.h"

using namespace std;

class Worker : public OSThread {

public:



	Worker(int serial_number, int number_of_nodes);
    virtual ~Worker();
    void init_RT();
    void init_neighbours_RT();
    void run();
    bool studentSend(void *args);
    bool studentRecv(void **args);
    void set_neighbour(int neighbour_serial_number);
    void kill_or_revive_neighbour(int neighbour_serial_number, int action);
    void print();
    void put_in_inbox(Message *message);
    bool is_RT_changed();
    bool is_neighbour(int worker_id);
    int getTotal_number_of_messages_delivered_to_the_thread_from_the_last_quantum() const
    {
        return _total_number_of_messages_delivered_to_the_thread_from_the_last_quantum;
    }

    void setTotal_number_of_messages_delivered_to_the_thread_from_the_last_quantum(int _total_number_of_messages_delivered_to_the_thread_from_the_last_quantum)
    {
        this->_total_number_of_messages_delivered_to_the_thread_from_the_last_quantum = _total_number_of_messages_delivered_to_the_thread_from_the_last_quantum;
    }

    bool getWas_blocked_in_last_run() const
    {
        return _was_blocked_in_last_run;
    }

    void setWas_blocked_in_last_run(bool _was_blocked_in_last_run)
    {
        this->_was_blocked_in_last_run = _was_blocked_in_last_run;
    }

    int getSerial_number() const
    {
        return _serial_number;
    }

    bool getKilled() const
    {
        return _killed;
    }

    void revive()
    {
        pthread_mutex_lock(&_worker_killed_lock);
        this->_killed = false;
        pthread_cond_signal(&_worker_killed_cond);
		pthread_mutex_unlock(&_worker_killed_lock);
    }

    RouterTable *getRoutering_table() const
    {
        return _routering_table;
    }

    void setStatus(int _status)
    {
        this->_status = _status;
    }

    int getStatus() const
    {
        return _status;
    }

    int get_Yielded_with_given_quanta() const
    {
        return _last_yielded_quanta;
    }

    bool is_inbox_empty()
    {
        return _inbox->is_empty();
    }

    Mailbox *getMailer_inbox() const
    {
        return _mailer_inbox;
    }

    void setIs_RT_changed(bool _is_RT_changed)
    {
        this->_is_RT_changed = _is_RT_changed;
    }

    void setIs_alive(bool _is_alive)
    {
        this->_is_alive = _is_alive;
    }

    void setMailer_inbox(Mailbox *_mailer_inbox)
    {
        this->_mailer_inbox = _mailer_inbox;
    }

    bool getActive() const
    {
        return _active;
    }

    void setActive(bool _active)
    {
        this->_active = _active;
    }

private:
    int 					_serial_number;
    int 					_number_of_nodes;
    vector<int>*			_neighbours;
    vector<int>*			_neighbours_killed;
    RouterTable *_routering_table;
    vector<RouterTable*> *_neighbours_routering_tables;
    bool _active;
    Mailbox *_inbox;
    Mailbox *_mailer_inbox;
    bool _is_RT_changed;
    bool _is_alive;
    int _last_yielded_quanta;

    pthread_mutex_t _inbox_empty_lock;
    pthread_cond_t _inbox_empty_cond;

    pthread_mutex_t m_quantaLock;
    pthread_cond_t m_quantaCond;

    pthread_mutex_t _inbox_mutex;

    pthread_mutex_t _worker_killed_lock;
    pthread_cond_t _worker_killed_cond;

    int _status;
    bool _last_message_was_RT;
    int	 _last_message_type;
    Message_System *_message_system_that_has_to_be_forwarded;
    bool _got_final_message;
    bool _killed;
    bool _system_just_initialized;
    bool _was_blocked_in_last_run;
    int _total_number_of_messages_delivered_to_the_thread_from_the_last_quantum;



    bool am_I_the_victim(int victim);

    bool is_first_iteration();
    bool update_current_RT();
    void insert_neighbour_RT(Message* message);
    void update_neighbours();
    void forward_message_to_closest_neighbour(Message_System* message_System);
    int get_closest_neighbour_that_is_not(int worker_id);
    Worker* get_neighbour_by_id(int id);
    void yield_if_needed();
    bool is_message_to_me(Message* message);
    void handle_message_to_myself(Message_System* message_System);
    void say(string text);
    bool is_die_message(Message_System* message_System);



};

#endif /* WORKER_H_ */
